package com.chuangke.common.db.query;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chuangke.common.db.query.domain.Condition;
import com.chuangke.common.db.query.domain.Group;
import com.chuangke.common.db.query.domain.Order;
import com.chuangke.common.db.query.domain.Query;
import com.chuangke.common.db.query.enums.JoinEnum;
import com.chuangke.common.db.query.enums.OperatorConstants;
import com.chuangke.common.exception.ChuangkeException;
import org.apache.commons.collections.CollectionUtils;

import java.util.List;

public class QueryBuilder {

	public static <T> QueryWrapper<T> createQueryWrapper(Query query) {
		QueryWrapper<T> qw = new QueryWrapper<>();

		buildQueryWrapperByCondition(qw, query.getJoin(), query.getConditions());

		buildQueryWrapperByGroup(qw, query.getJoin(), query.getGroups());

		return qw;
	}

	public static <T> void buildQueryWrapperByGroup(QueryWrapper<T> qw, String join, List<Group> groups) {
		if (CollectionUtils.isEmpty(groups)) {
			return;
		}

		for (Group group : groups) {
			buildQueryWrapperByGroup(qw, join, group);
		}
	}

	public static <T> void buildQueryWrapperByGroup(QueryWrapper<T> qw, String join, Group group) {
		if (JoinEnum.or.name().equals(join)) {
			qw.or(a -> {
				buildQueryWrapperByCondition(qw, group.getJoin(), group.getConditions());

				buildQueryWrapperByGroup(qw, group.getJoin(), group.getGroups());
			});
		} else {
			qw.and(a -> {
				buildQueryWrapperByCondition(qw, group.getJoin(), group.getConditions());

				buildQueryWrapperByGroup(qw, group.getJoin(), group.getGroups());
			});
		}
	}

	public static <T> void buildQueryWrapperByCondition(QueryWrapper<T> qw, String join, List<Condition> conditions) {
		if (CollectionUtils.isEmpty(conditions)) {
			return;
		}

		for (Condition condition : conditions) {
			condition.setColumn(StrUtil.toUnderlineCase(condition.getColumn()));
			buildQueryWrapper(qw, join, condition);
		}
	}

	@SuppressWarnings("unchecked")
	public static <T> void buildQueryWrapper(QueryWrapper<T> qw, String join, Condition condition) {
		if (condition == null || StrUtil.isBlank(condition.getOperator())
				|| StrUtil.isBlank(condition.getColumn())) {
			return;
		}

		switch (condition.getOperator()) {
		case OperatorConstants.eq:
			if (JoinEnum.or.name().equals(join)) {
				qw.or();
			}
			qw.eq(condition.getColumn(), condition.getValue());
			return;
		case OperatorConstants.like:
			if (JoinEnum.or.name().equals(join)) {
				qw.or();
			}
			qw.like(condition.getColumn(), condition.getValue());
			return;
		case OperatorConstants.notLike:
			if (JoinEnum.or.name().equals(join)) {
				qw.or();
			}
			qw.notLike(condition.getColumn(), condition.getValue());
			return;
		case OperatorConstants.rightLike:
			if (JoinEnum.or.name().equals(join)) {
				qw.or();
			}
			qw.likeRight(condition.getColumn(), condition.getValue());
			return;
		case OperatorConstants.leftLike:
			if (JoinEnum.or.name().equals(join)) {
				qw.or();
			}
			qw.likeLeft(condition.getColumn(), condition.getValue());
			return;
		case OperatorConstants.between:
			if (JoinEnum.or.name().equals(join)) {
				qw.or();
			}
			List<Object> bvalues = (List<Object>) condition.getValue();
			qw.between(condition.getColumn(), bvalues.get(0), bvalues.get(1));
			return;
		case OperatorConstants.notBetween:
			if (JoinEnum.or.name().equals(join)) {
				qw.or();
			}
			List<Object> nvalues = (List<Object>) condition.getValue();
			qw.notBetween(condition.getColumn(), nvalues.get(0), nvalues.get(1));
			return;
		case OperatorConstants.gt:
			if (JoinEnum.or.name().equals(join)) {
				qw.or();
			}
			qw.gt(condition.getColumn(), condition.getValue());
			return;
		case OperatorConstants.ge:
			if (JoinEnum.or.name().equals(join)) {
				qw.or();
			}
			qw.ge(condition.getColumn(), condition.getValue());
			return;
		case OperatorConstants.lt:
			if (JoinEnum.or.name().equals(join)) {
				qw.or();
			}
			qw.lt(condition.getColumn(), condition.getValue());
			return;
		case OperatorConstants.le:
			if (JoinEnum.or.name().equals(join)) {
				qw.or();
			}
			qw.le(condition.getColumn(), condition.getValue());
			return;
		case OperatorConstants.in:
			if (JoinEnum.or.name().equals(join)) {
				qw.or();
			}
			List<Object> ivalues = (List<Object>) condition.getValue();
			qw.in(condition.getColumn(), ivalues);
			return;
		case OperatorConstants.ne:
			if (JoinEnum.or.name().equals(join)) {
				qw.or();
			}
			qw.ne(condition.getColumn(), condition.getValue());
			return;
		case OperatorConstants.isNotNull:
			if (JoinEnum.or.name().equals(join)) {
				qw.or();
			}
			qw.isNotNull(condition.getColumn());
			return;
		case OperatorConstants.isNull:
			if (JoinEnum.or.name().equals(join)) {
				qw.or();
			}
			qw.isNull(condition.getColumn());
			return;
		case OperatorConstants.notIn:
			if (JoinEnum.or.name().equals(join)) {
				qw.or();
			}
			List<Object> noInvalues = (List<Object>) condition.getValue();
			qw.notIn(condition.getColumn(), noInvalues);
			return;
		default:
			throw new ChuangkeException(String.format("暂不支持的查询条件符号:%s", condition.getOperator()));
		}
	}

	public static <T> void buildQueryWrapperByOrder(QueryWrapper<T> qw, List<Order> orders) {
		if (CollectionUtils.isEmpty(orders)) {
			return;
		}

		for (Order order : orders) {
			buildQueryWrapperByOrder(qw, order);
		}
	}
	public static <T> void buildQueryWrapperByOrder(QueryWrapper<T> qw, Order order) {
		if (order == null || StrUtil.isBlank(order.getOperator())
				|| StrUtil.isBlank(order.getColumn())) {
			return;
		}
		switch (order.getOperator()) {
			case OperatorConstants.desc:
				qw.orderByDesc(order.getColumn());
				break;
			case OperatorConstants.asc:
				qw.orderByAsc(order.getColumn());
				break;
			default:
				throw new ChuangkeException(String.format("暂不支持的排序符号:%s", order.getOperator()));
		}

	}
}
